import CoreImage
import UIKit
import Metal
import MetalPerformanceShaders

class FilterEngine: ObservableObject {
    private let context: CIContext
    private let metalDevice: MTLDevice?
    
    init() {
        // Try to use Metal for better performance
        if let device = MTLCreateSystemDefaultDevice() {
            self.metalDevice = device
            self.context = CIContext(mtlDevice: device)
        } else {
            self.metalDevice = nil
            self.context = CIContext()
        }
    }
    
    enum FilterType: String, CaseIterable {
        case original = "Original"
        case warm = "Vintage Warm" 
        case fresh = "Fresh & Clean"
        case elegant = "Elegant Mono"
        case dramatic = "Dramatic"
        case soft = "Soft Portrait"
        case vivid = "Vivid Colors"
        case noir = "Film Noir"
        
        var displayName: String {
            return self.rawValue
        }
        
        var description: String {
            switch self {
            case .original:
                return "No filter applied"
            case .warm:
                return "Warm tones with vintage feel"
            case .fresh:
                return "Bright and vibrant"
            case .elegant:
                return "Sophisticated monochrome"
            case .dramatic:
                return "High contrast and bold"
            case .soft:
                return "Gentle skin enhancement"
            case .vivid:
                return "Enhanced saturation"
            case .noir:
                return "Classic black and white"
            }
        }
    }
    
    func applyFilter(to image: UIImage, filterType: FilterType, intensity: Float = 1.0) -> UIImage? {
        guard let ciImage = CIImage(image: image) else { return nil }
        
        let filteredImage: CIImage
        
        switch filterType {
        case .original:
            filteredImage = ciImage
        case .warm:
            filteredImage = applyWarmFilter(to: ciImage, intensity: intensity)
        case .fresh:
            filteredImage = applyFreshFilter(to: ciImage, intensity: intensity)
        case .elegant:
            filteredImage = applyElegantFilter(to: ciImage, intensity: intensity)
        case .dramatic:
            filteredImage = applyDramaticFilter(to: ciImage, intensity: intensity)
        case .soft:
            filteredImage = applySoftFilter(to: ciImage, intensity: intensity)
        case .vivid:
            filteredImage = applyVividFilter(to: ciImage, intensity: intensity)
        case .noir:
            filteredImage = applyNoirFilter(to: ciImage, intensity: intensity)
        }
        
        guard let cgImage = context.createCGImage(filteredImage, from: filteredImage.extent) else {
            return nil
        }
        
        return UIImage(cgImage: cgImage)
    }
    
    // MARK: - Filter Implementations
    
    private func applyWarmFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Color adjustments
        let colorFilter = CIFilter(name: "CIColorControls")!
        colorFilter.setValue(image, forKey: kCIInputImageKey)
        colorFilter.setValue(1.0 + (0.2 * intensity), forKey: kCIInputSaturationKey)
        colorFilter.setValue(0.1 * intensity, forKey: kCIInputBrightnessKey)
        colorFilter.setValue(1.0 + (0.15 * intensity), forKey: kCIInputContrastKey)
        
        guard let coloredImage = colorFilter.outputImage else { return image }
        
        // Warm color matrix
        let warmFilter = CIFilter(name: "CIColorMatrix")!
        warmFilter.setValue(coloredImage, forKey: kCIInputImageKey)
        warmFilter.setValue(CIVector(x: 1.0, y: 0.9, z: 0.8, w: 0), forKey: "inputRVector")
        warmFilter.setValue(CIVector(x: 0.1, y: 1.0, z: 0.9, w: 0), forKey: "inputGVector")
        warmFilter.setValue(CIVector(x: 0.05, y: 0.2, z: 1.0, w: 0), forKey: "inputBVector")
        warmFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
        
        // Add vintage vignette
        guard let warmImage = warmFilter.outputImage else { return coloredImage }
        return addVignette(to: warmImage, intensity: intensity * 0.3)
    }
    
    private func applyFreshFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Enhance saturation and vibrance
        let vibranceFilter = CIFilter(name: "CIVibrance")!
        vibranceFilter.setValue(image, forKey: kCIInputImageKey)
        vibranceFilter.setValue(0.5 * intensity, forKey: kCIInputAmountKey)
        
        guard let vibrantImage = vibranceFilter.outputImage else { return image }
        
        // Boost highlights
        let highlightFilter = CIFilter(name: "CIHighlightShadowAdjust")!
        highlightFilter.setValue(vibrantImage, forKey: kCIInputImageKey)
        highlightFilter.setValue(0.3 * intensity, forKey: "inputHighlightAmount")
        highlightFilter.setValue(0.1 * intensity, forKey: "inputShadowAmount")
        
        return highlightFilter.outputImage ?? vibrantImage
    }
    
    private func applyElegantFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Desaturate slightly
        let colorFilter = CIFilter(name: "CIColorControls")!
        colorFilter.setValue(image, forKey: kCIInputImageKey)
        colorFilter.setValue(1.0 - (0.3 * intensity), forKey: kCIInputSaturationKey)
        colorFilter.setValue(-0.05 * intensity, forKey: kCIInputBrightnessKey)
        colorFilter.setValue(1.0 + (0.2 * intensity), forKey: kCIInputContrastKey)
        
        guard let desaturatedImage = colorFilter.outputImage else { return image }
        
        // Add slight sepia tone
        let sepiaFilter = CIFilter(name: "CISepiaTone")!
        sepiaFilter.setValue(desaturatedImage, forKey: kCIInputImageKey)
        sepiaFilter.setValue(0.2 * intensity, forKey: kCIInputIntensityKey)
        
        return sepiaFilter.outputImage ?? desaturatedImage
    }
    
    private func applyDramaticFilter(to image: CIImage, intensity: Float) -> CIImage {
        // High contrast and clarity
        let contrastFilter = CIFilter(name: "CIColorControls")!
        contrastFilter.setValue(image, forKey: kCIInputImageKey)
        contrastFilter.setValue(1.0 + (0.4 * intensity), forKey: kCIInputContrastKey)
        contrastFilter.setValue(1.0 + (0.2 * intensity), forKey: kCIInputSaturationKey)
        
        guard let contrastImage = contrastFilter.outputImage else { return image }
        
        // Add unsharp mask for clarity
        let sharpenFilter = CIFilter(name: "CIUnsharpMask")!
        sharpenFilter.setValue(contrastImage, forKey: kCIInputImageKey)
        sharpenFilter.setValue(0.5 * intensity, forKey: kCIInputIntensityKey)
        sharpenFilter.setValue(2.5, forKey: kCIInputRadiusKey)
        
        return sharpenFilter.outputImage ?? contrastImage
    }
    
    private func applySoftFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Soft glow effect
        let blurFilter = CIFilter(name: "CIGaussianBlur")!
        blurFilter.setValue(image, forKey: kCIInputImageKey)
        blurFilter.setValue(2.0 * intensity, forKey: kCIInputRadiusKey)
        
        guard let blurredImage = blurFilter.outputImage else { return image }
        
        // Blend with original
        let blendFilter = CIFilter(name: "CISourceOverCompositing")!
        blendFilter.setValue(blurredImage, forKey: kCIInputBackgroundImageKey)
        blendFilter.setValue(image, forKey: kCIInputImageKey)
        
        // Reduce brightness slightly
        guard let blendedImage = blendFilter.outputImage else { return image }
        
        let brightnessFilter = CIFilter(name: "CIColorControls")!
        brightnessFilter.setValue(blendedImage, forKey: kCIInputImageKey)
        brightnessFilter.setValue(-0.1 * intensity, forKey: kCIInputBrightnessKey)
        brightnessFilter.setValue(1.0 + (0.1 * intensity), forKey: kCIInputSaturationKey)
        
        return brightnessFilter.outputImage ?? blendedImage
    }
    
    private func applyVividFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Boost saturation and vibrance
        let colorFilter = CIFilter(name: "CIColorControls")!
        colorFilter.setValue(image, forKey: kCIInputImageKey)
        colorFilter.setValue(1.0 + (0.3 * intensity), forKey: kCIInputSaturationKey)
        colorFilter.setValue(0.05 * intensity, forKey: kCIInputBrightnessKey)
        
        guard let coloredImage = colorFilter.outputImage else { return image }
        
        let vibranceFilter = CIFilter(name: "CIVibrance")!
        vibranceFilter.setValue(coloredImage, forKey: kCIInputImageKey)
        vibranceFilter.setValue(0.4 * intensity, forKey: kCIInputAmountKey)
        
        return vibranceFilter.outputImage ?? coloredImage
    }
    
    private func applyNoirFilter(to image: CIImage, intensity: Float) -> CIImage {
        // Convert to monochrome
        let monoFilter = CIFilter(name: "CIPhotoEffectNoir")!
        monoFilter.setValue(image, forKey: kCIInputImageKey)
        
        guard let noirImage = monoFilter.outputImage else { return image }
        
        // Enhance contrast for classic film look
        let contrastFilter = CIFilter(name: "CIColorControls")!
        contrastFilter.setValue(noirImage, forKey: kCIInputImageKey)
        contrastFilter.setValue(1.0 + (0.3 * intensity), forKey: kCIInputContrastKey)
        contrastFilter.setValue(-0.05 * intensity, forKey: kCIInputBrightnessKey)
        
        guard let contrastImage = contrastFilter.outputImage else { return noirImage }
        
        // Add film grain
        return addFilmGrain(to: contrastImage, intensity: intensity * 0.2)
    }
    
    // MARK: - Helper Effects
    
    private func addVignette(to image: CIImage, intensity: Float) -> CIImage {
        let vignetteFilter = CIFilter(name: "CIVignette")!
        vignetteFilter.setValue(image, forKey: kCIInputImageKey)
        vignetteFilter.setValue(intensity * 2.0, forKey: kCIInputIntensityKey)
        vignetteFilter.setValue(1.5, forKey: kCIInputRadiusKey)
        
        return vignetteFilter.outputImage ?? image
    }
    
    private func addFilmGrain(to image: CIImage, intensity: Float) -> CIImage {
        let noiseFilter = CIFilter(name: "CIRandomGenerator")!
        guard let noiseImage = noiseFilter.outputImage else { return image }
        
        let grainFilter = CIFilter(name: "CISourceOverCompositing")!
        grainFilter.setValue(image, forKey: kCIInputBackgroundImageKey)
        grainFilter.setValue(noiseImage, forKey: kCIInputImageKey)
        
        // Apply very subtle grain
        let opacityFilter = CIFilter(name: "CIColorMatrix")!
        if let grainImage = grainFilter.outputImage {
            opacityFilter.setValue(grainImage, forKey: kCIInputImageKey)
            opacityFilter.setValue(CIVector(x: 1, y: 1, z: 1, w: intensity * 0.03), forKey: "inputAVector")
        }
        
        return opacityFilter.outputImage ?? image
    }
    
    // MARK: - Thumbnail Generation
    
    func generateThumbnail(from image: UIImage, filterType: FilterType, size: CGSize = CGSize(width: 150, height: 150)) -> UIImage? {
        let resizedImage = image.resized(to: size)
        return applyFilter(to: resizedImage, filterType: filterType, intensity: 1.0)
    }
    
    // MARK: - Batch Processing
    
    func applyFilterAsync(to image: UIImage, filterType: FilterType, intensity: Float, completion: @escaping (UIImage?) -> Void) {
        DispatchQueue.global(qos: .userInitiated).async {
            let result = self.applyFilter(to: image, filterType: filterType, intensity: intensity)
            DispatchQueue.main.async {
                completion(result)
            }
        }
    }
}

extension UIImage {
    func resized(to size: CGSize) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { _ in
            self.draw(in: CGRect(origin: .zero, size: size))
        }
    }
    
    func cropped(to rect: CGRect) -> UIImage? {
        guard let cgImage = self.cgImage?.cropping(to: rect) else { return nil }
        return UIImage(cgImage: cgImage, scale: self.scale, orientation: self.imageOrientation)
    }
}